﻿#define DOWN_MIN_AUTOUPDATE_XML
using System;
using System.Xml;
using System.Net;
namespace BIN
{
    /// <summary>
    /// 更新AutoUpdate.exe文件的依据是比较本地的 Updatelist.xml和服务端的AutoUpdate.xml文件
    /// </summary>
    public  class  AutoUpdateFunc
    {
        private string _minXml = "AutoUpdate.xml";
        private string _svrMinXmlOnLocal = string.Empty;
        private readonly static string _defaultUpdateUrl = "http://your_default_update_url/vf/";
        private string localXmlPath = string.Empty ; //本地配置文件完全路径包含文件名
        private string ServerXml_local = string.Empty;//服务器配置文件存放在本地目录
        private string XmlFileName = string.Empty;//配置文件名，没有路径
        private XmlFiles _XmlObj = null; //本地配置文件的对象
        private bool _DownloadServerXmlFile = false; //是否成功下载服务器端配置文件
        public bool DownloadServerXmlFile { get { return _DownloadServerXmlFile; } }
        public string ServerXmlOnLocalPath //服务器配置文件在本地的完整路径包含文件名
        {
            get
            {
                return string.Format("{0}{1}{2}", 
                    ServerXml_local, ServerXml_local.EndsWith(@"\") ? "" : @"\", XmlFileName);
            }
        }
        ~AutoUpdateFunc()
        {
            if (_XmlObj != null) _XmlObj = null;
            if (_DownloadServerXmlFile)
            {
                if (System.IO.File.Exists(this.ServerXmlOnLocalPath))
                {
                    try
                    {
                        System.IO.File.Delete(this.ServerXmlOnLocalPath);
                    }
                    catch { }
                }
            }
        }
        public AutoUpdateFunc(string ConfigFile)
        {
            XmlFileName = ConfigFile;
            localXmlPath = AppDir + ConfigFile;
            _XmlObj = new XmlFiles(localXmlPath);
            if (NeedUpdate)DownloadXmlToLocal();
            DownloadAutoUpdateProg(); //下载最新的自动更新程序
        }
        #region "Static Methods"
        private static XmlFiles _xmlObj = null;
        public static XmlFiles SettingObj
        {
            get
            {
                if (null == _xmlObj)
                    _xmlObj = new XmlFiles(Common.CombineDir( AppDir, _FileName));
                return _xmlObj;
            }
        }
        private static string _FileName = "UpdateList.xml";
        public static string AppDir
        {
            get 
            {
                return Common.GetApplicationBaseDir();
            }
        }
        public static void ClearLocalFiles()
        {
            XmlNodeList lst= SettingObj.SelectNodes("//File");
            if (null != lst && lst.Count > 0)
            {
                for (int i = 0; i < lst.Count; i++)
                {
                    try
                    {
                        string KeyUpt = lst[i].Attributes["IsKeyUpt"].InnerXml.ToUpper();
                        if ("1" == KeyUpt)
                        {
                            string name = lst[i].Attributes["Name"].InnerText.ToUpper();
                            if ("CONNECTION.DLL" == name) continue;
                            lst[i].ParentNode.RemoveChild(lst[i]);
                        }
                    }
                    catch { }
                }
                SettingObj.Save();
            }
        }
        private static bool GetNeedUpdate()
        {
            try
            {
                string NeedUpt = SettingObj.GetNodeValue("//NeedUpdate").Trim().ToUpper();
                return (NeedUpt == "YES");
            }
            catch
            {
                return false;
            }
        }
        private static void SetNeedUpdate(bool NeedUpdate)
        {
            if (!(System.IO.File.Exists(AppDir + _FileName ))) return;
            System.Xml.XmlNodeList lst = SettingObj.GetNodeList("//NeedUpdate");
            if (null != lst && lst.Count > 0)
            {
                lst[0].Value = (NeedUpdate ? "YES" : "NO");
                SettingObj.Save();
            }
        }
        private static void CreateRequiredVersionField(XmlFiles xmlObj)
        {
            XmlNode node = xmlObj.FindNode("//RequiredVersion");
            if (null == node)
            {
                XmlNode pNode = xmlObj.FindNode("/Updater");
                if (null != pNode)
                {
                    XmlNode newNode = xmlObj.CreateElement("RequiredVersion");
                    newNode.InnerText = "2.0.0";
                    pNode.AppendChild(newNode);
                    xmlObj.Save();
                }
            }
        }
        private static void CreateContinueField(XmlFiles xmlObj)
        {
            XmlNode node = xmlObj.FindNode("//Continue");
            if (null == node)
            {
                XmlNode pNode = xmlObj.FindNode("/Updater");
                if (null != pNode)
                {
                    XmlNode newNode = xmlObj.CreateElement("Continue");
                    newNode.InnerText = "YES";
                    pNode.AppendChild(newNode);
                    xmlObj.Save();
                }
            }
        }
        private static bool GetContinueValue()
        {
            try
            {
              return SettingObj.GetNodeValue("//Continue").ToUpper().Trim()=="YES";
            }
            catch
            {
                CreateContinueField(SettingObj);
                return true;
            }
        }
        private static void SetContinueValue(bool Val)
        {
            CreateContinueField(SettingObj);
            XmlNode node = SettingObj.SelectSingleNode("//Continue");
            if (null != node)
            {
                node.InnerText = (Val ? "YES" : "NO");
                SettingObj.Save();
            }
        }
        public static string RequiredDBVersion
        {
            get { return GetRequiredDBVersion(); }
            set { SetRequirdDBVerion(value); }
        }
        public static bool CanContinue
        {
            get { return GetContinueValue(); }
            set { SetContinueValue(value); }
        }
        private static string GetRequiredDBVersion()
        {
            try
            {
                return SettingObj.GetNodeValue("//RequiredVersion").ToUpper().Trim();
            }
            catch
            {
                CreateRequiredVersionField(SettingObj);
                return "2.0.0";
            }
        }
        private static void SetRequirdDBVerion(string Version)
        {
            CreateRequiredVersionField(SettingObj);
            XmlNode node = SettingObj.SelectSingleNode("//RequiredVersion");
            if (null != node)
            {
                node.InnerText = Version;
                SettingObj.Save();
            }
        }
        public static string CurrVer
        {
            get
            {
                try
                {
                    return (SettingObj.GetNodeValue("//Version"));
                }
                catch
                {
                    return "0.0.0";
                }
            }
        }
        public static string MinVer
        {
            get
            {
                try
                {
                    return (SettingObj.GetNodeValue("//MinVersion"));
                }
                catch
                {
                    return "0.0.0";
                }
            }
        }
        public static string CurrVersion
        {
            get
            {
                try
                {
                    string Version = (SettingObj.GetNodeValue("//Version"));
                    string VersionSort = (SettingObj.GetNodeValue("//VersionSort"));
                    return (VersionSort + " " + Version);
                }
                catch
                {
                    return string.Empty;
                }
            }
        } 
        public static string GetUrl()
        {
            string tmpDir = Common.CombineDir(Common.AppDir, "temp");
            string url = string.Empty;
            try
            {
                url = SettingObj.GetNodeValue("//Url");
                if (!string.Empty.Equals(url,
                    StringComparison.OrdinalIgnoreCase))
                {
                    if (IsUrlOK(url, tmpDir)) return url;
                }
                else
                    throw new Exception("Url is empty!");
            }
            catch (Exception ex1)
            {
                try
                {
                    url = SettingObj.GetNodeValue("//Url1");
                    if (!string.Empty.Equals(url,
                        StringComparison.OrdinalIgnoreCase))
                    {
                        if (IsUrlOK(url, tmpDir)) return url;
                    }
                    else
                        throw new Exception("Url is empty!");
                }
                catch (Exception ex2)
                {
                    try
                    {
                        url = SettingObj.GetNodeValue("//Url2");
                        if (!string.Empty.Equals(url,
                            StringComparison.OrdinalIgnoreCase))
                        {
                            if (IsUrlOK(url, tmpDir)) return url;
                        }
                        else
                            throw new Exception("Url is empty!");
                    }
                    catch (Exception ex3)
                    {
                        try
                        {
                            url = SettingObj.GetNodeValue("//Url3");
                            if (!string.Empty.Equals(url,
                                StringComparison.OrdinalIgnoreCase))
                            {
                                if (IsUrlOK(url, tmpDir)) return url;
                            }
                            else
                                throw new Exception("Url is empty!");
                        }
                        catch (Exception ex4)
                        {
                            try
                            {
                                url = SettingObj.GetNodeValue("//Url4");
                                if (!string.Empty.Equals(url,
                                    StringComparison.OrdinalIgnoreCase))
                                {
                                    if (IsUrlOK(url, tmpDir)) return url;
                                }
                                else
                                    throw new Exception("Url is empty!");
                            }
                            catch (Exception ex5)
                            {
                                try
                                {
                                    url = SettingObj.GetNodeValue("//Url5");
                                    if (!string.Empty.Equals(url,
                                        StringComparison.OrdinalIgnoreCase))
                                    {
                                        if (IsUrlOK(url, tmpDir)) return url;
                                    }
                                    else
                                        throw new Exception("Url is empty!");
                                }
                                catch (Exception ex6)
                                {
                                    try
                                    {
                                        url = SettingObj.GetNodeValue("//Url6");
                                        if (!string.Empty.Equals(url,
                                            StringComparison.OrdinalIgnoreCase))
                                        {
                                            if (IsUrlOK(url, tmpDir)) return url;
                                        }
                                        else
                                            throw new Exception("Url is empty!");
                                    }
                                    catch (Exception ex7)
                                    {
                                        return string.Empty;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            return string.Empty;
        }
        private static bool IsUrlOK(string url, string tmpDir)
        {
            if (!url.EndsWith(@"/")) url += @"/";
            url += "AlertInfo.xml";
            string dest = Common.CombineDir(tmpDir, "AlertInfo.xml");
            if (Common.FileExists(dest)) System.IO.File.Delete(dest);
            WebClient webclt = null;
            try
            {
                webclt = new WebClient();
                if (!url.StartsWith("ftp:", StringComparison.OrdinalIgnoreCase))
                {
                    webclt.UseDefaultCredentials = true;
                }
                Common.CheckDownUrl(ref url, ref dest);
                webclt.DownloadFile(url, dest);
                return Common.FileExists(dest);
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                if (null != webclt) webclt.Dispose();
            }
        }
        private static bool IsUrlOK(string url)
        {
            if (string.Empty.Equals(url, StringComparison.OrdinalIgnoreCase)) return false;
            if (!url.EndsWith(@"/")) url += @"/";
            url += "AlertInfo.xml";
            string dest = Common.CombineDir(Common.AppDir, "AlertInfo.xml");
            if (Common.FileExists(dest)) System.IO.File.Delete(dest);
            WebClient webclt = null;
            try
            {
                webclt = new WebClient();
                if (!url.StartsWith("ftp:", StringComparison.OrdinalIgnoreCase))
                {
                    webclt.UseDefaultCredentials = true;
                }
                Common.CheckDownUrl(ref url, ref dest);
                webclt.DownloadFile(url, dest);
                return Common.FileExists(dest);
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                if (null != webclt) webclt.Dispose();
            }
        }
        private static string GetRootUrl()
        {
            string url = string.Empty;
            try
            {
                url= SettingObj.GetNodeValue("//RootUrl").Trim().ToUpper();
                if (IsUrlOK(url)) return url;
            }
            catch
            {
                try
                {
                    url = SettingObj.GetNodeValue("//RootUrl1").Trim().ToUpper();
                    if (IsUrlOK(url)) return url;
                }
                catch
                {
                    try
                    {
                        url = SettingObj.GetNodeValue("//RootUrl2").Trim().ToUpper();
                        if (IsUrlOK(url)) return url;
                    }
                    catch
                    {

                    }
                }
            }
            return _defaultUpdateUrl;
        }
        private static void SetRootUrl(string Url)
        {
            if (!(System.IO.File.Exists(AppDir + _FileName))) return;
            System.Xml.XmlNodeList lst = SettingObj.GetNodeList("//RootUrl");
            if (null != lst && lst.Count > 0)
            {
                lst[0].Value = Url;
                SettingObj.Save();
            }
        }
        private static void SetUrl(string  Url)
        {
            if (!(System.IO.File.Exists(AppDir + _FileName))) return;
            System.Xml.XmlNodeList lst = SettingObj.GetNodeList("//Url");
            if (null != lst && lst.Count > 0)
            {
                lst[0].Value = Url;
                SettingObj.Save();
            }
        }
        public static string RootUrl
        {
            get { return GetRootUrl(); }
            set { SetRootUrl(value); }
        }
        public static string UpdateUrl
        {
            get { return GetUrl(); }
            set { SetUrl(value); }
        }
        public static bool NeedUpdate //需要更新
        {
          get
          {
              return GetNeedUpdate();
           }
            set
            {
                SetNeedUpdate(value);
            }
        }
        #endregion
        /// <summary>
        /// 取服务器更新程序目录的URL地址
        /// </summary>
        private string __url = string.Empty;
        public string ServerXmlUrl
        {
            get
            {
                if (string.IsNullOrEmpty( __url))
                    __url = this.ServerXmlUrlPri;
                return __url;
            }
        }
        private string ServerXmlUrlPri
        {
            get
            {
                if (!Common.FileExists(localXmlPath))
                    return _defaultUpdateUrl;
                string url = string.Empty;
                try
                {
                    url = _XmlObj.GetNodeValue(@"//Url").Trim();
                    if (IsUrlOK(url)) return url;
                }
                catch
                {
                    try
                    {
                        url = _XmlObj.GetNodeValue(@"//Url1").Trim();
                        if (IsUrlOK(url)) return url;
                    }
                    catch
                    {
                        try
                        {
                            url = _XmlObj.GetNodeValue(@"//Url2").Trim();
                            if (IsUrlOK(url)) return url;
                        }
                        catch
                        {
                            try
                            {
                                url = _XmlObj.GetNodeValue(@"//Url3").Trim();
                                if (IsUrlOK(url)) return url;
                            }
                            catch
                            {
                                try
                                {
                                    url = _XmlObj.GetNodeValue(@"//Url4").Trim();
                                    if (IsUrlOK(url)) return url;
                                }
                                catch
                                {
                                    try
                                    {
                                        url = _XmlObj.GetNodeValue(@"//Url5").Trim();
                                        if (IsUrlOK(url)) return url;
                                    }
                                    catch
                                    {
                                        try
                                        {
                                            url = _XmlObj.GetNodeValue(@"//Url6").Trim();
                                            if (IsUrlOK(url)) return url;
                                        }
                                        catch
                                        {
                                            return _defaultUpdateUrl;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                return _defaultUpdateUrl;
            }
        }
        /// <summary>
        /// 是否有自动更新程序
        /// </summary>
        public bool HasAutoUpdateProg
        {
            get
            {
                return Common.FileExists(Common.CombineDir( AppDir , "AutoUpdate.exe"));
            }
        }
        public void InvokeAutoUpdate()
        {
            if (!(this.HasAutoUpdateProg) || !NeedUpdate  ) return;
            string AutoUptCmd = Common.CombineDir( AppDir , "AutoUpdate.exe");
            if (!(Common.FileExists(AutoUptCmd))) return;
            Common.BeginProcessArgs(AutoUptCmd, "/CALLFROMPROG", AppDir);
        }
        /// <summary>
        /// 下载UpdateList.xml文件
        /// </summary>
        /// <param name="Url"></param>
        private void DownUpdateListXmlToLocal(string Url)
        { 
           if(string.IsNullOrEmpty(ServerXml_local) )
           {
               ServerXml_local=Common.CombineDir( 
                 Environment.GetEnvironmentVariable("Temp"),"App\\" );//存放服务器配置文件的本地目录
               Common.CheckFolderExists(ServerXml_local);
           }
           WebOp.Download(Url, XmlFileName, ServerXml_local);
           _DownloadServerXmlFile = (Common.FileExists(
               string.Format("{0}{1}{2}", ServerXml_local,
               ServerXml_local.EndsWith(@"\") ? "" : @"\", XmlFileName)));
        }
        private void DownAutoUpdateXmlToLocal(string Url)
        {
            if (string.IsNullOrEmpty(_svrMinXmlOnLocal))
            {
                _svrMinXmlOnLocal = Common.CombineDir(
                   Common.AppDir, "temp\\App\\");
                Common.CheckFolderExists(_svrMinXmlOnLocal);
            }
            WebOp.Download(Url, _minXml, _svrMinXmlOnLocal);
            _svrMinXmlOnLocal = Common.CombineDir(_svrMinXmlOnLocal, _minXml);
        }
        private void DownloadXmlToLocal() //下载服务器的XML配置文件
        {
            string Url = this.ServerXmlUrl;
            if (string.Empty.Equals( Url, StringComparison.OrdinalIgnoreCase)) return;
#if !DOWN_MIN_AUTOUPDATE_XML
            DownUpdateListXmlToLocal(Url);
#else
            try
            {
                DownAutoUpdateXmlToLocal(Url);
            }
            catch
            {
                DownUpdateListXmlToLocal(Url);
            }
#endif
        }
        private bool FileNeedUpt(string shortFileName) // AutoUpdate.exe 程序是最新版本吗
        {
            string fileName = Common.CombineDir(AppDir, shortFileName);
            if (!Common.FileExists (fileName)) return true;
            string localVersion = GetLocalFileVersion(shortFileName);
            string SvrVersion = GetServerFileVersion(shortFileName);
            return (SvrVersion.CompareTo(localVersion) != 0);
        }
        private string GetLocalFileVersion(string FileName)//取本机自动更新程序版本
        {
           XmlNodeList lst= _XmlObj.GetNodeList(@"AutoUpdater/Files");
           int Count = lst.Count;
           for (int i = 0; i < Count; i++)
           {
               try
               {
                   if (FileName.Equals( lst[i].Attributes["Name"].Value, StringComparison.OrdinalIgnoreCase ))
                       return (lst[i].Attributes["Ver"].Value.ToString().Trim());
               }
               catch { }
           }
           return "0.0.0.0";
        }
        /// <summary>
        /// 从服务端的UpdateList.xml获取文件版本
        /// </summary>
        /// <param name="FileName"></param>
        /// <returns></returns>
        private string GetServerFileVersionFromUpdateList(string FileName)
        {
            if (!_DownloadServerXmlFile) DownloadXmlToLocal();
            if (!_DownloadServerXmlFile) throw new Exception("failture when downloading the server config file !");
            //if (!_DownloadServerXmlFile) throw new Exception(Language.CommonCls.AutoUpdateFunc_SetDownLoadError);
            XmlFiles SvrXmlObj = null;
            try
            {
                SvrXmlObj = new XmlFiles(this.ServerXmlOnLocalPath);
                System.Xml.XmlNodeList lst = SvrXmlObj.GetNodeList(@"AutoUpdater/Files");
                int Count = lst.Count;
                for (int i = 0; i < Count; i++)
                {
                    try
                    {
                        if (lst[i].Attributes["Name"].Value.ToString().Equals( FileName, StringComparison.OrdinalIgnoreCase))
                            return (lst[i].Attributes["Ver"].Value.ToString().Trim());
                    }
                    catch { }
                }
                return "0.0.0.0";
            }
            finally
            {
                if (null != SvrXmlObj) SvrXmlObj = null;
            }
        }
        /// <summary>
        /// 从AutoUpdate.xml获取某个文件的版本
        /// </summary>
        /// <param name="FileName"></param>
        /// <returns></returns>
        private string GetSvrFileVersionFromAutoUpdateXml(string FileName)
        {
            if (!Common.FileExists(_svrMinXmlOnLocal)) 
                DownloadXmlToLocal();
            if (!Common.FileExists(_svrMinXmlOnLocal))
                throw new Exception("No file indicated!");
            string xPath = string.Format("//Version//{0}", FileName);
            string version = XPathGet.GetValue(_svrMinXmlOnLocal, xPath);
            if (string.IsNullOrEmpty( version))
                return "0.0.0.0";
            else
                return version;
        }
        private string GetServerFileVersion(string FileName ) //取服务器更新程序版本
        {
#if !DOWN_MIN_AUTOUPDATE_XML
            return GetServerFileVersionFromUpdateList(FileName);
#else
            try
            {
                return GetSvrFileVersionFromAutoUpdateXml(FileName);
            }
            catch
            {
                return GetServerFileVersionFromUpdateList(FileName);
            }
#endif
        }
        private void DownloadAutoUpdateProgPri() //下载最新的自动更新程序
        { 
            string AptprogPath= Common.CombineDir( AppDir ,"AutoUpdate.exe");
            if (System.IO.File.Exists(AptprogPath))
            { 
               Common.ProgRunned("AutoUpdate.exe",true );
               try
               {
                   System.IO.File.Delete(AptprogPath);
               }
               catch { }
            }
            string Url = this.ServerXmlUrl;
            if (Url == "") return;
            WebOp.Download(Url, "AutoUpdate.exe", AppDir); //下载自动更新程序
        }
        private void DownLoadUpdateSilentProgPri()
        {
            string AptprogPath = Common.CombineDir( AppDir, "UpdateSilent.exe");
            if (System.IO.File.Exists(AptprogPath))
            {
                Common.ProgRunned("UpdateSilent.exe", true);
                try
                {
                    System.IO.File.Delete(AptprogPath);
                }
                catch { }
            }
            string Url = this.ServerXmlUrl;
            if (Url == "") return;
            WebOp.Download(Url, "UpdateSilent.exe", AppDir); //下载自动更新程序
        }
        private void DownLoadUpdateLib()
        {
            WebOp.Download(this.ServerXmlUrl, "UpdateLib.dll", AppDir);
        }
        public void DownloadAutoUpdateProg()
        {
            if (FileNeedUpt("AutoUpdate.exe"))
            {
                DownloadAutoUpdateProgPri();  //下载最新的自动更新程序
            }
            if (FileNeedUpt("UpdateSilent.exe"))
            {
                DownLoadUpdateSilentProgPri();
            }
        }
    }
}
